package Games;

import Client.Command;
import java.awt.Canvas;

import Client.GraphicPiece;

public class Othello extends AbstractFunctions {

	private static final int EMPTY = 2;
	private static final int DIMENSION = 8;
	private static final int N = 0;
	private static final int NE= 1;
	private static final int E = 2;
	private static final int SE= 3;
	private static final int S = 4;
	private static final int SW= 5;
	private static final int W = 6;
	private static final int NW= 7;

	protected static final int playerOne = 0;
	protected static final int playerTwo = 1;

	private BoardCanvas canvas;
	private GamesModel gamesModel;
	private GamesController gamesController;

	private OthelloMove root;

	private int rows = 8;
	private int cols = 8;

	public Othello(String player1, String selectedGame) {
		//Initialize the board
		board = new Board(cols,rows);
		gamesModel = new GamesModel(board,selectedGame);
		gamesModel.setPlayerOne(player1);
		setGameModel(gamesModel);
		//        GameFrame().getScoreView().setPlayerOne(player1);
		GameFrame().setGameModel(gamesModel);
		gamesController = new GamesController(this, gamesModel, GameFrame());

		//Initialize the Canvas where the board is drawn on.
		canvas = new BoardCanvas(GameFrame().getBoardView().getWidth(),GameFrame().getBoardView().getHeight(),cols,rows, gamesModel,gamesController);
		GameFrame().getBoardView().add(canvas);
		gamesController.setBoardCanvas(canvas);
	}

	public Canvas getCanvas() {
		return canvas;
	}
	@Override
	public void start() {
		// TODO Auto-generated method stub

	}

	public void updateBoard(String player, int move) {
		int[] flips = new int[NW+1];
		calcFlips(move, GamesController.gamesModel().getPlayersHashMap().get(player), flips);
		playMove(move, GamesController.gamesModel().getPlayersHashMap().get(player), flips);
	}

	protected static void calcFlips(int move, int player, int[] flips) {
		int x = xFromMove(move);
		int y = yFromMove(move);
		for (int i=1; i<=DIMENSION; i++) {
			doFlip(i, y-i, x  , otherPlayer(player), N , flips);
			doFlip(i, y-i, x+i, otherPlayer(player), NE, flips);
			doFlip(i, y  , x+i, otherPlayer(player), E , flips);
			doFlip(i, y+i, x+i, otherPlayer(player), SE, flips);
			doFlip(i, y+i, x  , otherPlayer(player), S , flips);
			doFlip(i, y+i, x-i, otherPlayer(player), SW, flips);
			doFlip(i, y  , x-i, otherPlayer(player), W , flips);
			doFlip(i, y-i, x-i, otherPlayer(player), NW, flips);
		}
	}
	private static void doFlip(int i, int y, int x, int other, int dir, int[] flips) {
		if (x<0 || x>DIMENSION-1 ||
				y<0 || y>DIMENSION-1) {
			if (flips[dir] == i-1)
				flips[dir]=0;
		} else if (board.getFieldValue(x, y)==other && flips[dir]==i-1) {
			flips[dir]++;
		} else if (board.getFieldValue(x, y)==EMPTY && flips[dir]==i-1) {
			flips[dir]=0;
		}
	}	
	protected static void playMove(int move, int player, int[] flips) {
		int x = xFromMove(move);
		int y = yFromMove(move);
		//		int player = nextPlayer);

		board.place(x, y, player);

		int dx = 0, dy = 0;
		for (int dir = N; dir <= NW; dir++) {
			switch (dir) {
			case N:	dx= 0; dy=-1; break;
			case NE:dx=+1; dy=-1; break;
			case E:	dx=+1; dy= 0; break;
			case SE:dx=+1; dy=+1; break;
			case S:	dx= 0; dy=+1; break;
			case SW:dx=-1; dy=+1; break;
			case W:	dx=-1; dy= 0; break;
			case NW:dx=-1; dy=-1; break;
			}
			for (int i = 1; i <= flips[dir]; i++) {
				board.place(x+dx*i, y+dy*i, player);
			}
		}
	}
	private static int xFromMove(int move) {
		return move%DIMENSION;
	}
	private static int yFromMove(int move) {
		return move/DIMENSION;
	}
	private static int otherPlayer(int player) {
		return player==playerOne ? playerTwo : playerOne;
	}

	@Override
	public void initiateBoard(boolean weBegin) {
		board.place(3, 3, weBegin?1:0);
		board.place(4, 4, weBegin?1:0);
		board.place(3, 4, weBegin?0:1);
		board.place(4, 3, weBegin?0:1);
	}

	@Override    
	public synchronized void chooseMove(int player) {
		int move = OthelloAI.chooseMove(player, board.getBoard());
		Command.move(move);
/*
		if (root==null) {
    		int free=0;
			int[][] localBoard = board.getBoard();
    		for (int move = 0; move < DIMENSION*DIMENSION; move++) {
    			if (localBoard[yFromMove(move)][xFromMove(move)]==EMPTY)
    				free++;
    		}

    		root = new OthelloMove(-1, player, localBoard, new int[NW-1], free);
    		System.out.println("Voor 8 seconden");
    		try {
				wait(8000);
			} catch (InterruptedException e) {
				System.out.println("InterruptedException");
			}
    	}
		System.out.println("NA 8 seconden");
    	root = root.chooseMove();
    	synchronized (OthelloMove.lock) {
    		OthelloMove.depthFree--;
    		OthelloMove.lock.notifyAll();
    	}
    	Command.move(root.getMove()); //*/
	}

	public void opponentMove(int move) {
		if (root==null)
			return;
		OthelloMove[] children = root.getChildren();
		for (int c = 0; c < children.length; c++) {
			if (children[c].getMove() == move)
				root = children[c];
			else
				children[c].kill();
		}
		synchronized (OthelloMove.lock) {
			OthelloMove.depthFree--;
			OthelloMove.lock.notifyAll();
		}
	}

	@Override
	public GraphicPiece getGraphicPiece(int player, int col, int row,
			int width, int height) {
		if (player==0) {
			return new BlackPiece(col, row, width, height);
		} else {
			return new WhitePiece(col, row, width, height);
		}
	}
	
	public GamesModel getGamesModel(){
    	return gamesModel;
    }
}
